<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="NGQlb" id="NGQlb"><span data-lake-id="u73baccf8" id="u73baccf8">典型回答</span></h1>
  <p data-lake-id="uc0916c7e" id="uc0916c7e"><br></p>
  <p data-lake-id="u6ebc7fd1" id="u6ebc7fd1"><span data-lake-id="u8a62a7ee" id="u8a62a7ee">这个问题其实是考察如何在Spring启动过程中做额外操作，其实有挺多做法的，这里就介绍几种比较常用的：</span></p>
  <p data-lake-id="uc3800b9c" id="uc3800b9c"><br></p>
  <h3 data-lake-id="KJ4EO" id="KJ4EO"><span data-lake-id="uc602131e" id="uc602131e">ApplicationReadyEvent</span></h3>
  <p data-lake-id="u9130524e" id="u9130524e"><br></p>
  <p data-lake-id="u3a9fdd77" id="u3a9fdd77"><span data-lake-id="ucaaa7553" id="ucaaa7553">在应用程序启动时，可以通过监听应用启动事件，或者在应用的初始化阶段，将需要缓存的数据加载到缓存中。</span></p>
  <p data-lake-id="u9ee94cd7" id="u9ee94cd7"><span data-lake-id="uc1eebad3" id="uc1eebad3">​</span><br></p>
  <p data-lake-id="uc992db1c" id="uc992db1c"><span data-lake-id="ue2a0feab" id="ue2a0feab">ApplicationReadyEvent</span><span data-lake-id="u140c6f3c" id="u140c6f3c"> 是 Spring Boot 框架中的一个事件类，它表示应用程序已经准备好接收请求，即应用程序已启动且上下文已刷新。这个事件是在 </span><span data-lake-id="u672c2194" id="u672c2194">ApplicationContext</span><span data-lake-id="u85e49dbe" id="u85e49dbe"> 被初始化和刷新，并且应用程序已经准备好处理请求时触发的。</span></p>
  <p data-lake-id="u6f998ae1" id="u6f998ae1"><span data-lake-id="u0e77d645" id="u0e77d645">​</span><br></p>
  <p data-lake-id="u7df19bef" id="u7df19bef"><span data-lake-id="u04553824" id="u04553824">基于ApplicationReadyEvent，我们可以在应用程序完全启动并处于可用状态后执行一些初始化逻辑。使用 @EventListener 注解或实现 ApplicationListener 接口来监听这个事件。例如，使用 @EventListener 注解：</span></p>
  <p data-lake-id="u56519fe5" id="u56519fe5"><span data-lake-id="u6bbc1d00" id="u6bbc1d00">​</span><br></p>
  <pre lang="java"><code>
@EventListener(ApplicationReadyEvent.class)
public void preloadCache() {
    // 在应用启动后执行缓存预热逻辑
    // ...
}

</code></pre>
  <h3 data-lake-id="gtBkG" id="gtBkG"><span data-lake-id="u17bb4eae" id="u17bb4eae">Runner</span></h3>
  <p data-lake-id="u97a9bb4c" id="u97a9bb4c"><br></p>
  <p data-lake-id="uf9a02510" id="uf9a02510"><span data-lake-id="u08fa1a99" id="u08fa1a99">如果你不想直接监听</span><strong><span data-lake-id="ud0722091" id="ud0722091" class="lake-fontsize-11" style="color: rgb(15, 15, 15)">ApplicationReadyEvent，在SpringBoot中，也可以通过</span></strong><strong><span data-lake-id="uce07abed" id="uce07abed" style="color: rgb(15, 15, 15)">CommandLineRunner</span></strong><span data-lake-id="ucd923db1" id="ucd923db1" class="lake-fontsize-12" style="color: rgb(15, 15, 15)"> 和 </span><strong><span data-lake-id="udc4df688" id="udc4df688" style="color: rgb(15, 15, 15)">ApplicationRunner</span></strong><span data-lake-id="u6f54081d" id="u6f54081d" class="lake-fontsize-12" style="color: rgb(15, 15, 15)"> 来实现这个功能。</span></p>
  <p data-lake-id="u038d6429" id="u038d6429"><span data-lake-id="u51261661" id="u51261661" class="lake-fontsize-12" style="color: rgb(15, 15, 15)">​</span><br></p>
  <p data-lake-id="u955937b1" id="u955937b1"><strong><span data-lake-id="u03a9fcbe" id="u03a9fcbe" style="color: rgb(15, 15, 15)">CommandLineRunner</span></strong><span data-lake-id="u31fea1f5" id="u31fea1f5" class="lake-fontsize-12" style="color: rgb(15, 15, 15)"> 和 </span><strong><span data-lake-id="u922f55a1" id="u922f55a1" style="color: rgb(15, 15, 15)">ApplicationRunner</span></strong><span data-lake-id="ua01d397e" id="ua01d397e" class="lake-fontsize-12" style="color: rgb(15, 15, 15)"> 是 Spring Boot 中用于在应用程序启动后执行特定逻辑的接口。这解释听上去就像是专门干这个事儿的。</span></p>
  <p data-lake-id="ub478f930" id="ub478f930"><span data-lake-id="uf6bee823" id="uf6bee823" class="lake-fontsize-12" style="color: rgb(15, 15, 15)">​</span><br></p>
  <pre lang="java"><code>
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        // 在应用启动后执行缓存预热逻辑
        // ...
    }
}

</code></pre>
  <p data-lake-id="u5e7dcdf3" id="u5e7dcdf3"><br></p>
  <pre lang="java"><code>
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class MyApplicationRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 在应用启动后执行缓存预热逻辑
        // ...
    }
}

</code></pre>
  <p data-lake-id="u65d60456" id="u65d60456"><br></p>
  <p data-lake-id="u81a4a7d0" id="u81a4a7d0"><span data-lake-id="u42b20cf6" id="u42b20cf6">CommandLineRunner 和 ApplicationRunner的调用，是在SpringApplication的run方法中，这个我们在下面这个介绍过：</span></p>
  <p data-lake-id="u1ac3cfd8" id="u1ac3cfd8"><br></p>
  <p data-lake-id="u9b10286b" id="u9b10286b"><span data-lake-id="u25203a35" id="u25203a35">其实就是callRunners(context, applicationArguments);的实现：</span></p>
  <p data-lake-id="u4fe9632c" id="u4fe9632c"><span data-lake-id="u99cd47f9" id="u99cd47f9">​</span><br></p>
  <pre lang="java"><code>
private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List&lt;Object&gt; runners = new ArrayList&lt;&gt;();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet&lt;&gt;(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

</code></pre>
  <p data-lake-id="u3ac07fb5" id="u3ac07fb5"><br></p>
  <h3 data-lake-id="BIIrA" id="BIIrA" style="text-align: left"><strong><span data-lake-id="uc1a685d5" id="uc1a685d5" class="lake-fontsize-12" style="color: var(--tw-prose-bold)">使用</span></strong><strong><span data-lake-id="u106f09e6" id="u106f09e6" class="lake-fontsize-12" style="color: var(--tw-prose-code)">InitializingBean</span></strong><strong><span data-lake-id="u68eb0ddd" id="u68eb0ddd" class="lake-fontsize-12" style="color: var(--tw-prose-bold)">接口</span></strong></h3>
  <p data-lake-id="u76ecb106" id="u76ecb106"><br></p>
  <p data-lake-id="ub5808b87" id="ub5808b87" style="text-align: left"><span data-lake-id="ue39ca70f" id="ue39ca70f">实现 InitializingBean 接口，并在 afterPropertiesSet 方法中执行缓存预热的逻辑。这样，Spring 在初始化 Bean 时会调用 afterPropertiesSet 方法。</span></p>
  <p data-lake-id="u9054065d" id="u9054065d" style="text-align: left"><span data-lake-id="u47ff7b8d" id="u47ff7b8d">​</span><br></p>
  <pre lang="java"><code>
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class CachePreloader implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        // 执行缓存预热逻辑
        // ...
    }
}

</code></pre>
  <p data-lake-id="u5aa9aa3f" id="u5aa9aa3f"><br></p>
  <p data-lake-id="u436cd3e2" id="u436cd3e2"><span data-lake-id="uf1d2973e" id="uf1d2973e">这个方法的调用我们在Spring的启动流程中也介绍过，不再展开了。</span></p>
  <p data-lake-id="u7343f230" id="u7343f230"><span data-lake-id="ub0506bc6" id="ub0506bc6">​</span><br></p>
  <p data-lake-id="u08578d22" id="u08578d22"><br></p>
  <p data-lake-id="u2b97c7ca" id="u2b97c7ca"><br></p>
  <p data-lake-id="ua8f0faa3" id="ua8f0faa3" style="text-align: left"><strong><span data-lake-id="ue45322d1" id="ue45322d1" class="lake-fontsize-12" style="color: var(--tw-prose-bold)">使用</span></strong><strong><span data-lake-id="u9cac32e5" id="u9cac32e5" class="lake-fontsize-12" style="color: var(--tw-prose-code)">@PostConstruct</span></strong><strong><span data-lake-id="u65b6eef9" id="u65b6eef9" class="lake-fontsize-12" style="color: var(--tw-prose-bold)">注解</span></strong></p>
  <p data-lake-id="u519f95d9" id="u519f95d9"><span data-lake-id="u2ed6f03c" id="u2ed6f03c">​</span><br></p>
  <p data-lake-id="ub96eeed7" id="ub96eeed7"><span data-lake-id="ubae098e2" id="ubae098e2">类似的，我们还可以使用 @PostConstruct 注解标注一个方法，该方法将在 Bean 的构造函数执行完毕后立即被调用。在这个方法中执行缓存预热的逻辑。</span></p>
  <p data-lake-id="u1952ab5c" id="u1952ab5c"><span data-lake-id="u06fb5806" id="u06fb5806">​</span><br></p>
  <pre lang="java"><code>
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;

@Component
public class CachePreloader {

    @PostConstruct
    public void preloadCache() {
        // 执行缓存预热逻辑
        // ...
    }
}

</code></pre>
  <p data-lake-id="u91ab292e" id="u91ab292e"><span data-lake-id="u735a5396" id="u735a5396">​</span><br></p>
  <p data-lake-id="u70a82363" id="u70a82363"><span data-lake-id="udce244b4" id="udce244b4">这个我们也介绍过，也不展开了。</span></p>
  <p data-lake-id="u4d55a6ee" id="u4d55a6ee"><span data-lake-id="uf2d4bf40" id="uf2d4bf40">​</span><br></p>
 </body>
</html>